
#include "Server.h"

#define buffer_size 64000

Server::Server(int server_port, string socket_type, int ipv) {
    if (socket_type == "tcp") {
        socketType = SOCK_STREAM;
    } else {
        socketType = SOCK_DGRAM;
    }

    if (ipv == 4) {
        IPv = AF_INET;
    } else {
        IPv = AF_INET6;
    }

    port = server_port;
    max_clients = 10;
    bound = false;

    BuildServer();
}

in_port_t Server::get_in_port(struct sockaddr *sa) {
    if (sa->sa_family == AF_INET) {
        return (((struct sockaddr_in*) sa)->sin_port);
    }

    return (((struct sockaddr_in6*) sa)->sin6_port);
}



void Server::SetMaxClients(int n) {
    max_clients = n;
    BuildServer();
}

void Server::Listen() {
#ifdef DEBUG
    cout << "Listening...\n";
#endif
    listen(server_sockfd, max_clients);

}

int Server::Accept() {
    int c;
    c = GetFreeClient();
    socklen_t sz;
    sz = sizeof client_addresses[c];

    int cl;
    cl = accept(server_sockfd, &client_addresses[c], &sz);
    

#ifdef DEBUG
    if (cl == -1) {
        cout << "Accept failed\n";
    } else {
        cout << "Client Accepted\n" << "Client number is: " << c << "\n";
    }
#endif

    if(cl > -1){
    client_sockfds[c] = cl;
    return c;
    }
    else{
      return -1;
    }
}


void Server::Send(int client, void* data, int length) {
    send(client_sockfds[client], data, length, 0);
}



int Server::Receive(int client, void* buffer, int bufferSize) {
    int recvcode;
    bzero(buffer, bufferSize);
    recvcode = recv(client_sockfds[client], buffer, bufferSize, 0);
    if (recvcode <= 0) {
        RemoveClient(client);
    }
    return recvcode;
}

bool Server::IsClientConnected(int client) {
    if (client_sockfds[client] == 0) {
        return false;
    } else return true;
}

int Server::ClientCount() {
    int count = 0;
    for (int client = 0; client < max_clients; client++) {
        if (IsClientConnected(client)) {
            count++;
        }
    }
    return count;
}

void Server::RemoveClient(int client) {
    close(client_sockfds[client]);
    client_sockfds[client] = 0;
}

int Server::GetFreeClient() {
    for (int c = 0; c < max_clients; c++) {
        if (!IsClientConnected(c)) {
            return c;
        }
    }
    return -1;
}

bool Server::Close(){
  return close(server_sockfd);
}





void Server::BuildServer() {

    int binderr;

    if (bound) {
        close(server_sockfd);
    }

    int yes = 1;

    client_sockfds = new int[max_clients];

    client_addresses = new struct sockaddr[max_clients];

    setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
            sizeof (int));


    if (IPv == AF_INET) {

        bzero(&server_addressV4, sizeof server_addressV4);

        server_addressV4.sin_family = IPv;
        server_addressV4.sin_addr.s_addr = INADDR_ANY;
        server_addressV4.sin_port = htons(port);
        server_sockfd = socket(IPv, socketType, 0);

        binderr = bind(server_sockfd, (struct sockaddr*) &server_addressV4, sizeof server_addressV4);
    } else {
        bzero(&server_addressV6, sizeof server_addressV6);

        server_addressV6.sin6_family = IPv;
        server_addressV6.sin6_addr = in6addr_any;
        server_addressV6.sin6_port = htons(port);
        server_sockfd = socket(IPv, socketType, 0);

        binderr = bind(server_sockfd, (struct sockaddr*) &server_addressV6, sizeof server_addressV6);
    }
    bound = true;

#ifdef DEBUG
    if (binderr == 0) {
        cout << "Bind Successful\n";
    } else {
        cout << "Bind Failed\n";
    }
#endif

}
